package com.cloudeasy.post.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cloudeasy.api.constant.PermissionConstant;
import com.cloudeasy.api.enums.ResultCodeEnum;
import com.cloudeasy.api.exception.CloudEasyException;
import com.cloudeasy.api.util.ResultUtil;
import com.cloudeasy.api.vo.PageResult;
import com.cloudeasy.api.vo.Result;
import com.cloudeasy.api.vo.label.LabelVO;
import com.cloudeasy.api.vo.post.PostVO;
import com.cloudeasy.api.vo.post.SimpleUserInfoVO;
import com.cloudeasy.core.bean.JwtParser;
import com.cloudeasy.post.client.LabelClient;
import com.cloudeasy.post.client.UserClient;
import com.cloudeasy.post.dto.PostDTO;
import com.cloudeasy.post.po.Post;
import com.cloudeasy.post.po.PostLabel;
import com.cloudeasy.post.service.PostLabelService;
import com.cloudeasy.post.service.PostService;
import com.cloudeasy.post.service.expand.SimpleUserInfoService;
import com.cloudeasy.post.util.IPageUtil;
import com.cloudeasy.post.util.PostUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

@RestController
@CrossOrigin
public class PostController extends BaseController {
    private final PostService postService;

    private final JwtParser jwtParser;

    private final SimpleUserInfoService simpleUserInfoService;

    private final PostLabelService postLabelService;

    private final LabelClient labelClient;

    @Autowired
    public PostController(UserClient userClient, PostService postService, JwtParser jwtParser, SimpleUserInfoService simpleUserInfoService, PostLabelService postLabelService, LabelClient labelClient) {
        super(userClient);
        this.postService = postService;
        this.jwtParser = jwtParser;
        this.simpleUserInfoService = simpleUserInfoService;
        this.postLabelService = postLabelService;
        this.labelClient = labelClient;
    }

    /**
     * 发帖
     *
     * @param authentication {@link Authentication}
     * @param postDTO        {@link PostDTO}
     * @return {@link Result<Boolean>}
     */
    @PostMapping
    public Result<Boolean> save(Authentication authentication, @RequestBody @Validated PostDTO postDTO) {
        String userId = (String) jwtParser.getOnBody(authentication, "userId");
        return ResultUtil.success(postService.save(userId, postDTO));
    }

    /**
     * 删帖
     *
     * @param id 帖子Id
     * @return {@link Boolean}
     */
    @DeleteMapping("/{id}")
    public Result<Boolean> delete(Authentication authentication, @PathVariable("id") String id) {
        String userId = (String) jwtParser.getOnBody(authentication, "userId");
        Post post = postService.getById(id);
        if (post == null) {
            throw new CloudEasyException(ResultCodeEnum.REPEAT_ERROR);
        }
        // 如果不是自己的帖子
        if (!post.getAuthorId().equals(userId)) {
            Result<Boolean> result = getBooleanResult(PermissionConstant.DELETE_POST, Collections.singletonList(post.getArea()), userId);
            if (!result.getCode().equals(ResultCodeEnum.SUCCESS.getCode())) {
                return result;
            }
        }
        return ResultUtil.success(postService.removeById(post));
    }

    /**
     * 获取当前用户的帖子
     *
     * @param authentication {@link Authentication}
     * @return {@link List<PostVO>}的{@link Result}
     */
    @GetMapping
    public Result<List<PostVO>> myPostList(Authentication authentication) {
        SimpleUserInfoVO simpleUserInfoVO = simpleUserInfoService.obtainSimpleUserInfo(authentication);
        List<Post> posts = postService.getByAuthorId(simpleUserInfoVO.getId());
        List<SimpleUserInfoVO> simpleUserInfoVOS = Collections.singletonList(simpleUserInfoVO);
        List<PostVO> postVOS = PostUtil.convert(posts, simpleUserInfoVOS);
        loadLabel(postVOS);
        return ResultUtil.success(postVOS);
    }

    /**
     * 分页获取当前用户的帖子
     *
     * @param authentication {@link Authentication}
     * @param page           页数
     * @param size           每页大小
     * @return {@link List<PostVO>}的{@link Result}
     */
    @GetMapping("/{page}/{size}")
    public Result<PageResult<PostVO>> myPostPage(Authentication authentication,
                                                 @PathVariable("page") Integer page,
                                                 @PathVariable("size") Integer size) {
        SimpleUserInfoVO simpleUserInfoVO = simpleUserInfoService.obtainSimpleUserInfo(authentication);
        IPage<Post> postIPage = postService.getByAuthorIdPage(simpleUserInfoVO.getId(), page, size);
        List<SimpleUserInfoVO> simpleUserInfoVOS = Collections.singletonList(simpleUserInfoVO);

        PageResult<PostVO> postVOPageResult = PostUtil.convert(postIPage, simpleUserInfoVOS);
        loadLabel(postVOPageResult.getRecords());
        return ResultUtil.success(postVOPageResult);
    }

    /**
     * 获取指定Id的帖子
     *
     * @param id 帖子Id
     * @return {@link Result<PostVO>}
     */
    @GetMapping("/one/{id:\\d+}")
    public Result<PostVO> get(@PathVariable("id") String id) {
        Post post = postService.getById(id);
        if (post == null) {
            return ResultUtil.success();
        }
        List<SimpleUserInfoVO> simpleUserInfoVOS = simpleUserInfoService.obtainSimpleUserInfo(Collections.singletonList(post.getAuthorId()));
        return ResultUtil.success(PostUtil.convert(Collections.singletonList(post), simpleUserInfoVOS).get(0));
    }

    /**
     * 获取某作者的帖子
     *
     * @param authorId 作者Id
     * @return {@link List<PostVO>}的{@link Result}
     */
    @GetMapping("/{authorId}")
    public Result<List<PostVO>> myPostList(@PathVariable("authorId") String authorId) {
        List<Post> posts = postService.getByAuthorId(authorId);
        List<SimpleUserInfoVO> simpleUserInfoVOS = simpleUserInfoService.obtainSimpleUserInfo(Collections.singletonList(authorId));
        List<PostVO> postVOS = PostUtil.convert(posts, simpleUserInfoVOS);
        loadLabel(postVOS);
        return ResultUtil.success(postVOS);
    }

    /**
     * 分页获取某作者的帖子
     *
     * @param authorId 作者Id
     * @param page     页数
     * @param size     每页大小
     * @return {@link List<PostVO>}的{@link Result}
     */
    @GetMapping("/{authorId}/{page}/{size}")
    public Result<PageResult<PostVO>> myPostPage(@PathVariable("authorId") String authorId,
                                                 @PathVariable("page") Integer page,
                                                 @PathVariable("size") Integer size) {
        IPage<Post> posts = postService.getByAuthorIdPage(authorId, page, size);
        List<SimpleUserInfoVO> simpleUserInfoVOS = simpleUserInfoService.obtainSimpleUserInfo(Collections.singletonList(authorId));
        PageResult<PostVO> postVOPageResult = PostUtil.convert(posts, simpleUserInfoVOS);
        loadLabel(postVOPageResult.getRecords());
        return ResultUtil.success(postVOPageResult);
    }

    /**
     * 获取某区域内的帖子
     *
     * @param area 区域
     * @param type 类型
     * @param asc  正序排序字段
     * @param desc 倒序排序字段
     * @return {@link List<PostVO>}的{@link Result}
     */
    @GetMapping("/list")
    public Result<List<PostVO>> list(@RequestParam("area") String area,
                                     @RequestParam(value = "type", required = false) Integer type,
                                     @RequestParam(value = "asc", required = false) String[] asc,
                                     @RequestParam(value = "desc", required = false) String[] desc) {
        QueryWrapper<Post> queryWrapper = PostUtil.compose(area, type, asc, desc);
        List<Post> posts = postService.list(queryWrapper);
        List<String> authorIds = posts.stream().map(Post::getAuthorId).collect(Collectors.toList());
        if (authorIds.size() == 0) {
            return ResultUtil.success(new ArrayList<>());
        }
        List<SimpleUserInfoVO> simpleUserInfoVOS = simpleUserInfoService.obtainSimpleUserInfo(authorIds);
        List<PostVO> postVOS = PostUtil.convert(posts, simpleUserInfoVOS);
        loadLabel(postVOS);
        return ResultUtil.success(postVOS);
    }

    /**
     * 分页获取某区域内的帖子
     *
     * @param area 区域
     * @param type 类型
     * @param asc  正序排序字段
     * @param desc 倒序排序字段
     * @param page 页数
     * @param size 每页大小
     * @return {@link PageResult<PostVO>}的{@link Result}
     */
    @GetMapping("/list/{page}/{size}")
    public Result<PageResult<PostVO>> page(@RequestParam("area") String area,
                                           @RequestParam(value = "type", required = false) Integer type,
                                           @RequestParam(value = "asc", required = false) String[] asc,
                                           @RequestParam(value = "desc", required = false) String[] desc,
                                           @PathVariable("page") Integer page,
                                           @PathVariable("size") Integer size) {
        QueryWrapper<Post> queryWrapper = PostUtil.compose(area, type, asc, desc);
        IPage<Post> postTempIPage = IPageUtil.compose(page, size);

        IPage<Post> postIPage = postService.page(postTempIPage, queryWrapper);
        List<String> authorIds = postIPage.getRecords().stream().map(Post::getAuthorId).collect(Collectors.toList());
        if (authorIds.size() == 0) {
            return ResultUtil.success(PageResult.newInstance(postIPage.getTotal(), postIPage.getPages()));
        }
        List<SimpleUserInfoVO> simpleUserInfoVOS = simpleUserInfoService.obtainSimpleUserInfo(authorIds);
        PageResult<PostVO> postVOPageResult = PostUtil.convert(postIPage, simpleUserInfoVOS);
        loadLabel(postVOPageResult.getRecords());
        return ResultUtil.success(postVOPageResult);
    }

    /**
     * 推荐
     *
     * @param authentication {@link Authentication}
     * @return {@link List<PostVO>}的{@link Result}
     */
    @GetMapping("/recommend")
    public Result<List<PostVO>> recommend(Authentication authentication) {
        String userId = (String) jwtParser.getOnBody(authentication, "userId");
        List<Post> posts = postService.recommend(userId);
        if (posts.size() == 0) {
            return ResultUtil.success();
        }
        List<String> authorIds = posts.stream().map(Post::getAuthorId).distinct().collect(Collectors.toList());
        List<SimpleUserInfoVO> simpleUserInfoVOS = simpleUserInfoService.obtainSimpleUserInfo(authorIds);
        List<PostVO> postVOS = PostUtil.convert(posts, simpleUserInfoVOS);
        loadLabel(postVOS);
        return ResultUtil.success(postVOS);
    }

    /**
     * 添加标签
     *
     * @param postVOS {@link List<PostVO>}
     */
    private void loadLabel(List<PostVO> postVOS) {
        List<String> postIds = postVOS.stream().map(PostVO::getId).collect(Collectors.toList());
        List<PostLabel> postLabels = postLabelService.getByPostIds(postIds);
        List<String> labelIds = postLabels.stream().map(PostLabel::getLabelId).distinct().collect(Collectors.toList());
        Result<List<LabelVO>> result = labelClient.list(labelIds, null, null, null, null);
        if (!result.getCode().equals(ResultCodeEnum.SUCCESS.getCode())) {
            throw new CloudEasyException(Objects.requireNonNull(ResultCodeEnum.get(result.getCode())));
        }
        Map<String, LabelVO> labelVOMap = result.getData().stream().collect(Collectors.toMap(LabelVO::getId, labelVO -> labelVO, (o, o2) -> o));
        postVOS.forEach(postVO -> {
            String id = postVO.getId();
            List<LabelVO> labelVOList = new ArrayList<>();
            postLabels.removeIf(postLabel -> {
                if (postLabel.getPostId().equals(id)) {
                    labelVOList.add(labelVOMap.get(postLabel.getLabelId()));
                    return true;
                }
                return false;
            });
            postVO.setLabels(labelVOList);
        });
    }
}
